#ifndef _AIMBOT_H_
#define _AIMBOT_H_

#include "armor.h"
#include "Classify.h"

class Aimbot {

 private:
    static constexpr int BLUE_BINARY_THRES = 150;
    static constexpr int RED_BINARY_THRES = 150;
    static constexpr int BLUE_CHANNEL_THRESH = 150;
    static constexpr int RED_CHANNEL_THRESH = 150;
    static constexpr double MAX_LIGHTBAR_AREA = 9000.0;
    static constexpr double MIN_LIGHTBAR_AREA = 1.0;
    static constexpr double MIN_LIGHTBAR_RATIO = 1.0;
    static constexpr double MIN_ASPECT_BIG_RATIO = 3.7;
    static constexpr double MAX_ASPECT_BIG_RATIO = 8.0;
    static constexpr double MIN_ASPECT_SMALL_RATIO = 1.5;
    static constexpr double MAX_ASPECT_SMALL_RATIO = 3.7;
    static constexpr double MAX_LENGTH_RATIO = 1.5;
    static constexpr double MAX_LIGHTBAR_ANGLE = 60.0;
    static constexpr double MAX_LIGHTBAR_DELTA = 15.0;
    static constexpr double MAX_ARMOR_ANGLE = 15.0;
    static constexpr double CAMERA_fy = 1060.06364500185;
    static constexpr int MAX_CANDIDATE_NUM = 5;

 private:
    struct ErrorScore{
        /// 总误差分数
        double sum_error_score = 0;

        /// 距离误差分数
        double dis_error_score = 0.0;

        /// 装甲板误差分数
        double ratio_error_score = 0.0;

        /// 两灯条高度比例误差分数
        double bar_len_ratio_error_score = 0.0;

        /// 两灯条倾斜度之差误差分数
        double bar_delta_angle_error_score = 0.0;

        /// 装甲板的灯条与矩形的相似程度造成的误差分数
        double similarity_error_score =  0.0;

        /// 装甲板中心到图像中心的x轴距离误差分数，未置用
        double x_axis_bias_error_score = 0.0;

        /// 装甲板倾斜程度误差分数
        double armor_angle_error_score = 0.0;
    };

    struct ErrorScoreComp{
        bool operator() (const std::tuple<Armor, ErrorScore>& a, const std::tuple<Armor, ErrorScore>& b)
        {
            return std::get<1>(a).sum_error_score < std::get<1>(b).sum_error_score;
        }
    };

 private:
    Classify classifier;

 public:
    Aimbot();
    void
    run(cv::Mat &img, Armor::Color enemy_color, std::vector<Armor> &armors, int max_armor_size = MAX_CANDIDATE_NUM);

 private:
    static void
    processImage(const cv::Mat &src, Armor::Color enemy_color, cv::Mat &processed_image);

    static void
    findLightbars(const cv::Mat &img, const cv::Mat &processed_image, Armor::Color mcu_color,
                  std::vector<Armor::Lightbar> &lightbars);

    void
    matchArmors(const cv::Mat &img, const std::vector<Armor::Lightbar> &lightbars,
                std::vector<Armor> &armors);

    static void gradeArmors(std::vector<Armor> &armors, int max_armor_num);

    static void
    thresh_img(const cv::Mat &src, cv::Mat &out, Armor::Color color, int gray_thresh, int color_channel_thresh);
    static void adjustLightBarAngle(float elli_angle, double &bar_angle);
    static void judgeLightbarColor(Armor::Lightbar &lightbar, const cv::Mat &src);
    static void adjustLightBarRect(cv::RotatedRect &rect);
    static inline bool checkLightbarSize(const std::vector<Armor::Lightbar> &lightbars);
    static double get_distance_score(double distance);

};

#endif //_AIMBOT_H_
